Aller au contenu principal

Plateau

OLEM est fourni avec 2 types de plateaux : le premier est composé de carrés, le second de triangles formant des hexagones.

Untitled

Untitled

Pour faciliter l'utilisation de ces plateaux dans les jeux, le module board fournit les structures de données et l'API que nous utilisons pour nos propres jeux. Un éditeur de niveaux permet aussi de créer des niveaux avec une interface graphique.

Pour présenter l'API et les structures de données, nous partirons des plus petites unités pour arriver jusqu'au plateau entier.

Les plateaux et leurs composants​

Éléments​

Un élément représente quelque chose qui se trouve sur le plateau. Cela peut être :

  • OLEM
  • un objet physique (pièce de jeu), comme un mur, une figurine, des ressources
  • des données liées à une position précise, invisibles pour les joueurs mais utilisables par le code du jeu. Par exemple, dans Guardian & Thieves, les positions où des trésors peuvent apparaître sont enregistrées dans le niveau, mais les trésors eux-mêmes sont générés par le code au chargement du niveau.

Structure de données

Un élément est un objet qui a :

  • un type, stocké sous forme de chaîne de caractères
  • des paramètres personnalisables, qui ont :
    • un nom (la clé), sous forme de chaîne de caractères
    • une valeur associée à ce nom, sous forme de chaîne de caractères (comme une table de hachage ou un objet JSON)

API

"""
Constructeur de la classe

:param type_string: type, chaîne de caractères
"""
Element(type_string)

"""
Renvoie le paramètre type de l'élément. Donne le même résultat que get_param("type").
"""
get_type()

"""
Renvoie la valeur du paramètre donné

:param param_name: nom du paramètre à lire

Renvoie la valeur associée, sous forme de chaîne de caractères
"""
get_param(param_name)

"""
Modifie la valeur d'un paramètre. Si un paramètre du même nom existe
déjà, sa valeur est remplacée, sinon il est créé.

:param param_name: nom du paramètre
:param value: valeur associée au nom, sous forme de chaîne de caractères
"""
set_param(param_name, value)

Conteneurs​

Pour placer des éléments sur le plateau, on les stocke dans des conteneurs. Il existe 3 types de conteneurs :

  • le nœud (Node)
  • la case (Cell)
  • la bordure (Border)

Ces types sont expliqués plus en détail dans la section Tuiles ci-dessous.

Structure de données

Un conteneur est une liste d'éléments.

API

"""
Vérifie si le conteneur contient au moins un élément d'un
type donné

:param type: type à vérifier

Renvoie un booléen
"""
has_element_type(type)

"""
Ajoute un élément au conteneur.

:param element: objet Element à stocker dans le conteneur
"""
add_element(element)

"""
Retire un élément du conteneur. L'élément n'est PAS détruit.

:param element: objet Element à retirer du conteneur
"""
remove_element(element)

"""
Retire tous les éléments du conteneur.
"""
clear_elements()

"""
Renvoie la liste des éléments du conteneur.
"""
get_elements()

"""
Renvoie le premier élément du type donné.

:param string_type: type à chercher

Renvoie un objet Element
"""
get_element_by_type(string_type)

"""
Renvoie tous les éléments du type donné.

:param string_type: type à chercher

Renvoie une liste d'objets Element
"""
get_elements_by_type(string_type)

"""
Vérifie si le conteneur contient des éléments.

Renvoie un booléen
"""
is_empty()

Tuiles​

Les tuiles sont les unités de base que l'on répète pour créer un plateau. Leur forme dépend du type de plateau, mais elles suivent toutes une structure commune, construite avec les conteneurs présentés ci-dessus :

  • les nœuds sont des positions entre les cases du plateau, où OLEM peut se trouver (d'autres éléments peuvent aussi y être placés). Il y a un seul nœud par tuile
  • les cases sont, eh bien, les cases classiques d'un jeu de plateau
  • les bordures sont les zones entre les cases, où l'on peut par exemple placer des murs

Structure de données

Une tuile contient :

  • ses coordonnées (x, y) sur le plateau
  • un nœud
  • un tableau de cases
  • un tableau de bordures

Tuile carrée

Untitled

Pour le plateau composé de carrés, une tuile est définie ainsi :

Diagramme sans nom.drawio(1).png

avec :

  • 1, le nœud
  • 2, la case (ici, il n'y en a qu'une)
  • 3, la bordure du haut
  • 4, la bordure de gauche

Tuiles triangulaires

Untitled

hex_tile.png

avec :

  • 1 le nœud
  • 2 les cases
  • 3 les bordures

API

"""
Renvoie une bordure de la tuile

:param id: sur un plateau carré, 0 est la bordure horizontale du haut, 1 la bordure verticale de gauche
Renvoie un conteneur
"""
get_border(id)

"""
Renvoie la case de la tuile

Renvoie un conteneur
"""
get_cell()

"""
Renvoie le nœud de la tuile

Renvoie un conteneur
"""
get_node()

"""
Renvoie la coordonnée x de la tuile
"""
get_x()

"""
Renvoie la coordonnée y de la tuile
"""
get_y()

"""
Vérifie si les cases, le nœud et les bordures sont tous vides

Renvoie un booléen
"""
is_empty()

Plateau​

Un plateau est un objet qui a :

  • un nombre de colonnes
  • un nombre de lignes
  • des tuiles d'une dimension donnée (largeur et hauteur, en mm)
  • un nom
  • un tableau de paramètres personnalisables
  • un tableau de tuiles

En plaçant plusieurs tuiles côte à côte, on obtient cette structure (capture de l'éditeur de niveaux) :

booard_coord.svg

REMARQUE : avec cette structure, certains conteneurs sont en fait en dehors du plateau, car certains nœuds sont sur le bord du plateau

"""
Crée un plateau carré vide
NB : voir genericboard.load_board() pour charger un plateau créé avec l'éditeur de niveaux

:param rows: nombre de lignes
:param columns: nombre de colonnes
:param tile_width: largeur d'une tuile en mm
:param tile_height: hauteur d'une tuile en mm

Renvoie un objet squareboard
"""
squareboard(rows, columns, tile_width, tile_height)

"""
Affiche toutes les tuiles du plateau, avec un chiffre par tuile.
0 indique une tuile vide, 1 une tuile non vide
"""
print()

"""
Détruit l'objet plateau
NB : pour l'instant, il faut l'appeler manuellement pour éviter une fuite
mémoire. Nous cherchons un moyen de le détruire automatiquement, car
c'est un problème quand le script plante.
"""
__del__()

"""
Renvoie le nombre de lignes du plateau

Renvoie un entier
"""
get_row_count()

"""
Renvoie le nombre de colonnes du plateau

Renvoie un entier
"""
get_column_count()

"""
Vérifie si une position est valide sur le plateau
:param x: coordonnée x sur le plateau
:param y: coordonnée y sur le plateau

Renvoie un booléen
"""
is_position_within_board(x, y)

"""
Renvoie la tuile à une position donnée
:param x: coordonnée x sur le plateau
:param y: coordonnée y sur le plateau

Renvoie un objet tile, ou None si la tuile n'existe pas
"""
get_tile(x, y)

"""
Renvoie le nom du niveau

Renvoie une chaîne de caractères
"""
get_name()

"""
Renvoie la valeur du paramètre donné

:param param_name: nom du paramètre à lire

Renvoie la valeur associée, sous forme de chaîne de caractères
"""
get_param(param_name)

"""
Modifie la valeur d'un paramètre. Si un paramètre du même nom existe
déjà, sa valeur est remplacée, sinon il est créé.

:param param_name: nom du paramètre
:param value: valeur associée au nom, sous forme de chaîne de caractères
"""
set_param(param_name, value)

########################################
# Non implémenté ou non testé

get_tile_dimension
get_tiles
get_neighbor_tiles
get_border_from_tile(tile, direction)
get_border_from_position(x, y, direction)

Fonctions statiques​

Ces fonctions ne s'appellent pas sur les objets

"""
Crée un plateau à partir d'un fichier json généré par l'éditeur de niveaux

:param path_to_file: chemin du plateau dans le système de fichiers

Renvoie un objet squareboard
"""
genericboard.load_board(path_to_file)

Exemple​

Exemple simple​

import genericboard
import olem

TYPE_START = "start"
TYPE_WALL = "wall"
TYPE_END = "end"

def find_starting_pos(b):
for y in range(b.get_row_count()):
for x in range(b.get_column_count()):
tile = b.get_tile(x, y)
node = tile.get_node()

if (node.has_element_type(TYPE_START)):
print("found start at " + str(x) + " " + str(y))
return (x, y)

def is_node_walkable(board, x, y):
board_edge = False
if not board.is_position_within_board(x, y):
board_edge = True
if not board.is_position_within_board(x - 1, y):
board_edge = True
if not board.is_position_within_board(x, y - 1):
board_edge = True

if board_edge:
print("board edge is not walkable")
return False

has_wall = False
tile = board.get_tile(x, y)
if tile.get_node().has_element_type(TYPE_WALL):
has_wall = True
if tile.get_border(0).has_element_type(TYPE_WALL):
has_wall = True
if tile.get_border(1).has_element_type(TYPE_WALL):
has_wall = True

if(has_wall):
print("target tile has walls")
return False

print("looking left")
tile = board.get_tile(x - 1, y)
if tile.get_border(0).has_element_type(TYPE_WALL):
return False

print("looking up")
tile = board.get_tile(x, y - 1)
if tile.get_border(1).has_element_type(TYPE_WALL):
return False

return True

def get_command():
msg = olem.gmsg_wait_for_message()

if msg == "up":
return (0, -1)

if msg == "down":
return (0, 1)

if msg == "left":
return (-1, 0)

if msg == "right":
return (1, 0)

return (0, 0)

def end_reached(board, current_position):
tile = board.get_tile(current_position[0], current_position[1])
return tile.get_node().has_element_type(TYPE_END)

print("Board tester")

b = genericboard.load_board("/tmp/board_tester")
b.print()

starting_position = find_starting_pos(b)
current_position = starting_position

while not end_reached(b, current_position):
command = get_command()
if is_node_walkable(b, current_position[0] + command[0], current_position[1] + command[1]):
current_position = (current_position[0] + command[0], current_position[1] + command[1])
print("Moved to " + str(current_position[0]) + " " + str(current_position[1]))
else:
print("Node " + str(current_position[0] + command[0]) + " " + str(current_position[1] + command[1]) + " is not walkable")

print("End reached")
b.__del__()